共计 3746 个字符,预计需要花费 10 分钟才能阅读完成。
一. 类的分类
在前面一章我们简单介绍了一些类的分类
1. 新式类
- 继承了
object
的类以及该类的子类, 都是新式类 (Python3 中统一都是新式类) - 在 Python3 中如果一个类没有继承任何类, 则 默认会继承
object
类, 也就是Python3 中所有的类 都是 新式类
🍔在 "Python3" 中
class Default: # 默认继承 "object"
pass
print(Default.__bases__) # (<class 'object'>,)
2. 经典类
- 没有继承
object
的类以及该类的子类, 都是经典类 (只有 Python2 中才区分新式类和经典类) - 在 Python2 中如果一个类没有继承任何类, 它 不会继承
object
类, 所以Python2 中才有经典类
🍔在 "Python2" 中
class Default(object): # 新式类
pass
class Animal: # 经典类
pass
🍔"Python2" 中 "print" 语法
print Default.__bases__ # (<class 'object'>,)
print Animal.__bases__ # ()
ps : 新式类与经典类的属性查找顺序是不一样的
二. 菱形继承问题
上面说到 Python 支持多继承, 但新式类与经典类的属性查找顺序是不一样的
java 语言中,它不支持多继承,只支持继承一个父类
python 语言,支持多继承,比如 A(B,C,D)
1. 非菱形结构
-
非菱形结构下, 经典类与新式类的属性 查找顺序是一样的
-
如果继承关系为非菱形结构,则会按照先找 B 这一条分支,然后再找 C 这一条分支,最后找 D 这一条分支的顺序直到找到我们想要的属性
-
非菱形结构 (两条查询路径最后分别继承了 F1 和 F4)
class F1:
def s1(self):
print('F1:s1')
def s2(self):
print('F1:s2')
class F2(F1):
# def s1(self):
# print('F2:s1')
def s2(self):
print('F2:s2')
class F4():
def s1(self):
print('F4:s1')
def s2(self):
print('F4:s2')
class F3(F2,F4):
def s1(self):
super().s1() # 调用父类的 s1 方法, 到底使用了哪个父类的 s1
def s2(self):
print('F3:s2')
f1 = F3()
f1.s1() # F1:s1
- 查找顺序 : F3 ===> F2 ===> F1
2. 菱形结构
- 如果继承关系为菱形结构,即子类的父类最后继承了同一个类,那么属性的查找方式有两种:
- 新式类 -----> 广度优先
- 经典类 -----> 深度优先
1、新式类 -----> 广度优先
- 不找多个类最后继承的同一个类,直接去找下一个父类
__mro__
: 只有新式类才有的属性, 可查看属性查找的顺序
class G(object):
# def test(self):
# print('from G')
pass
class E(G):
# def test(self):
# print('from E')
pass
class B(E):
# def test(self):
# print('from B')
pass
class F(G):
# def test(self):
# print('from F')
pass
class C(F):
# def test(self):
# print('from C')
pass
class D(G):
# def test(self):
# print('from D')
pass
class A(B, C, D):
def test(self):
print('from A')
obj = A()
obj.test()
print(A.__mro__)
''' 查找顺序
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <type 'object'>)
'''
2、经典类 -----> 深度优先
- 从左到右选路, 一条路走到黑
#coding:utf-8
# python2 解释器
class G():
pass
def test(self):
print('G---test')
class F(G):
pass
# def test(self):
# print('FFF---test')
class E(G):
pass
# def test(self):
# print('EEE---test')
class D(G):
pass
# def test(self):
# print('DDD---test')
class B(E):
pass
# def test(self):
# print('BBB---test')
class C(F):
pass
# def test(self):
# print('CCC---test')
class A(B,C,D):
pass
# def test(self):
# print('AAA---test')
a=A()
a.test() # G---test
三. 小示例
1. 新式类
-
菱形结构示例 (子类最后继承了同样的类, 都继承了 A1 和 A2), 可以看成两个菱形
class A1:
def foo(self):
print('A1_foo')
class A2:
def foo(self):
print("A2_foo")
def bar(self):
print("A2_bar")
class B1(A1, A2):
pass
class B2(A1, A2):
def bar(self):
print("B2_bar")
class C(B1, B2):
pass
c = C()
c.foo() # A1_foo
c.bar() # B2_bar
print(C.__mro__)
''' 输出
(<class '__main__.C'>, <class '__main__.B1'>, <class '__main__.B2'>, <class '__main__.A1'>, <class '__main__.A2'>, <class 'object'>)
'''
c.foo()
的查找顺序 : C ==> B1 ===> B2 ==> A1c.bar()
的查找顺序 : C ==> B1 ==> B2
2. 经典类
#coding:utf-8
# python2.7 解释器
class A1():
def foo(self):
print 'A1_foo'
class A2():
def foo(self):
print "A2_foo"
def bar(self):
print "A2_bar"
class B1(A1, A2):
pass
class B2(A1, A2):
def bar(self):
print "B2_bar"
class C(B1, B2):
pass
c = C()
c.foo() # A1_foo
c.bar() # A2_bar
c.foo()
的查找顺序 : C ==> B1 ===> A1c.bar()
的查找顺序 : C ==> B1 ==> A1 ===> A2
四. c3 算法与 mro
1. 简介
为了实现继承,python 会在 MRO 列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止
而这个 MRO 列表的构造是通过一个 C3 线性化算法 来实现的
我们不去深究这个算法的数学原理,它实际上就是合并所有父类的 MRO 列表并遵循如下三条准则 :
- 子类会先于父类被检查
- 多个父类会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类
2.__mro__
方法使用
其实上面我们已经使用了这种方法, 下面再补充一点
- 只有 新式类 才可以使用 (Python2中的类如果没继承 object 就无法使用)
[类名]__mro__
: 打印属性查找顺序, 是一个元组[类名].mro()
: 打印属性查找顺序, 是一个列表
🍔Python2 中
#coding:utf-8
class C(object): # 继承 object 类, 如果不继承, 调用 mro 方法会报错
def run(self):
print "run_C"
class B(C):
pass
class A(B):
pass
a = A()
a.run() # run_C
print A.__mro__
# (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <type 'object'>)
print A.mro()
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <type 'object'>]
🍔Python3 中
class C: # 已经自动继承了 object 类
def run(self):
print("run_C")
class B(C):
pass
class A(B):
pass
a = A()
a.run() # run_C
print(A.__mro__)
# (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>)
print(A.mro())
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]
正文完